﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using DotNet.DevOps.Tasks.AssemblyInfo.Updaters;
using DotNet.DevOps.Tasks.AssemblyInfo.Updaters.VersionUpdaters;
using DotNet.DevOps.Tasks.Util;
using Microsoft.Build.Framework;

namespace DotNet.DevOps.Tasks.AssemblyInfo
{
    public interface IAssemblyInfo
    {
        bool AddIfMissing { get; set; }
        bool AutoUpdateCopyrightYear { get; set; }
        bool AutoIncrementLastFileVersionNumber { get; set; }
        bool AutoIncrementLastVersionNumber { get; set; }
        string Files { get; set; }
        string AssemblyDescription { get; set; }
        string AssemblyCompany { get; set; }
        string AssemblyConfiguration { get; set; }
        string AssemblyCulture { get; set; }
        string AssemblyProduct { get; set; }
        string AssemblyTitle { get; set; }
        string AssemblyTrademark { get; set; }
        string AssemblyCopyright { get; set; }
        string AssemblyFileVersion { get; set; }
        string AssemblyVersion { get; set; }
    }

    /// <summary>
    /// Set and/or auto-updates Assembly info entries.
    /// Can autoincrement the version/fileversion number by 1 if activated.
    /// Can autoupdate the copyright year.
    /// 
    /// Default behaviour:
    /// * Adds entry if missing.
    /// * Updates copyright year.
    /// 
    /// </summary>
    /// <example>
    /// import-module .\DotNet.DevOps.Tasks.dll
    /// 
    /// $task = New-Object DotNet.DevOps.Tasks.AssemblyInfo.AssemblyInfo -Property @{
    ///                                                                         Files="AssemblyInfo.cs" 
    ///                                                                         AssemblyFileVersion="$(BUILD_NUMBER)" 
    ///                                                                         AssemblyVersion="1.0.0.0"  
    ///                                                                         AssemblyCopyright="Copyright © Master Garrett 2011" 
    ///                                                                         AutoUpdateCopyrightYear="false" 
    ///                                                                         AutoIncrementLastVersionNumber="true"
    ///                                                                     }
    /// $result = $task.Execute()
    /// </example>
    /// <example>
    /// <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    /// 
    ///  <Import Project="$(libs)\DotNet.DevOps.Tasks.Targets" />
    /// 
    ///  <Target Name="Build">
    /// 
    ///    <AssemblyInfo    Files="AssemblyInfo.cs" 
    ///                     AssemblyFileVersion="$(BUILD_NUMBER)" 
    ///                     AssemblyVersion="1.0.0.0"  
    ///                     AssemblyCopyright="Copyright © Master Garrett 2011" 
    ///                     AutoUpdateCopyrightYear="false" 
    ///                     AutoIncrementLastVersionNumber="true"/>
    /// 
    ///  </Target>
    /// 
    /// </Project>
    /// </example>
    public class AssemblyInfo : ITask, IAssemblyInfo
    {
        public IBuildEngine BuildEngine { get; set; }
        public ITaskHost HostObject { get; set; }

        /// <summary>
        /// Default true, set to false if you want the build to do nothing if an entry is missing. A warning will be displayed however.
        /// </summary>
        [Standard]
        public bool AddIfMissing { get; set; }

        /// <summary>
        /// Default true,  will replace any year in the Copyright string to the current year.
        /// </summary>
        [Standard]
        public bool AutoUpdateCopyrightYear { get; set; }

        /// <summary>
        /// Default false, will increment last segment of the existing version number by one.
        /// </summary>
        [Standard]
        public bool AutoIncrementLastFileVersionNumber { get; set; }

        /// <summary>
        /// Default false, will increment last segment of the existing version number by one.
        /// </summary>
        [Standard]
        public bool AutoIncrementLastVersionNumber { get; set; }

        /// <summary>
        /// The file(s) to update.
        /// </summary>
        [Required]
        public string Files { get; set; }

        /// <summary>
        /// Value of the AssemblyDescription entry.
        /// </summary>
        [Standard]
        public string AssemblyDescription { get; set; }
        /// <summary>
        /// Value of the AssemblyCompany entry.
        /// </summary>
        [Standard]
        public string AssemblyCompany { get; set; }
        /// <summary>
        /// Value of the AssemblyConfiguration entry.
        /// </summary>
        [Standard]
        public string AssemblyConfiguration { get; set; }
        /// <summary>
        /// Value of the AssemblyCulture entry.
        /// </summary>
        [Standard]
        public string AssemblyCulture { get; set; }
        /// <summary>
        /// Value of the AssemblyProduct entry.
        /// </summary>
        [Standard]
        public string AssemblyProduct { get; set; }
        /// <summary>
        /// Value of the AssemblyTitle entry.
        /// </summary>
        [Standard]
        public string AssemblyTitle { get; set; }
        /// <summary>
        /// Value of the AssemblyTrademark entry.
        /// </summary>
        [Standard]
        public string AssemblyTrademark { get; set; }

        /// <summary>
        /// Value of the AssemblyCopyright entry.
        /// </summary>
        [Special]
        public string AssemblyCopyright { get; set; }
        /// <summary>
        /// Value of the AssemblyFileVersion entry.
        /// </summary>
        [Special]
        public string AssemblyFileVersion { get; set; }
        /// <summary>
        /// Value of the AssemblyVersion entry.
        /// </summary>
        [Special]
        public string AssemblyVersion { get; set; }

        private IEnumerable<PropertyUpdater> updaters;

        private ILog Log { get; set; }

        public AssemblyInfo()
        {
            Log = new MSBuildLogger(this);
            Init();
        }

        public AssemblyInfo(ILog logger)
        {
            Log = logger;
            Init();
        }

        private void Init()
        {
            AddIfMissing = true;
            AutoUpdateCopyrightYear = true;
            AutoIncrementLastFileVersionNumber = false;
            AutoIncrementLastVersionNumber = false;
            updaters = new List<PropertyUpdater>
                           {
                               new StandardUpdater(this, Log),
                               new CopyrightUpdater(this, Log),
                               new FileVersionUpdater(this, Log),
                               new VersionUpdater(this, Log)
                           };
        }

        public bool Execute()
        {
            try
            {
                this.ValidateNumberOfEmptyNotRequiredStringProperties( minimumWithValue: 1);

                var files = Files.GetValidFilenames();

                files.ToList().ForEach(UpdateProperties);
            }
            catch (Exception ex)
            {
                Log.LogError(ex);
                return false;
            }

            return true;
        }

        private void UpdateProperties(string filename)
        {
            var fileContent = File.ReadAllText(filename);

            Log.LogInfo(string.Format("Modifying: {0}",filename));

            updaters.ToList().ForEach(updater => fileContent = updater.UpdateProperties(fileContent));

            File.WriteAllText(filename, fileContent);
        }
    }
}
